package org.maxgroundstation.groundstation.view;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

import org.maxgroundstation.groundstation.GroundStation;
import org.maxgroundstation.groundstation.comm.CommandSender;

/**
 * A panel for connection controls.
 * @author Scott Davis
 * 
 * Copyright (C) 2010  Scott Davis
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@SuppressWarnings("serial")
public class ConnectionPanel extends JPanel {

    // Data members
    private GroundStation gs;
    private JLabel connectionMessageLabel;
    private JButton connectionButton;
    private JTextField commandIPField;
    private JTextField commandPortField;
    private JTextField serviceTCPPortInputField;
    private JTextField serviceUDPPortInputField;
    
    /**
     * Constructor
     * @param gs the ground station.
     */
    public ConnectionPanel(GroundStation gs) {
        super();
        
        // Initialize data members.
        this.gs = gs;
        
        // Set layout.
        setLayout(new BorderLayout());
        
        // Set border.
        setBorder(new TitledBorder("Robot Connection"));
        
        // Create connection message panel.
        JPanel connectionMessagePanel = new JPanel();
        add(connectionMessagePanel, BorderLayout.NORTH);

        // Create connection message label.
        connectionMessageLabel = new JLabel("Robot not connected", JLabel.CENTER);
        connectionMessagePanel.add(connectionMessageLabel);

        // Create the connection panel.
        JPanel connectionPanel = new JPanel(new GridLayout(4, 1, 0, 0));
        add(connectionPanel, BorderLayout.CENTER);

        // Create command IP panel.
        JPanel commandIPPanel = new JPanel();
        commandIPPanel.setLayout(new BoxLayout(commandIPPanel, BoxLayout.X_AXIS));
        connectionPanel.add(commandIPPanel);

        // Create command IP label.
        JLabel commandIPLabel = new JLabel("Command IP Address:");
        commandIPPanel.add(commandIPLabel);
        commandIPPanel.add(Box.createHorizontalStrut(10));

        // Create command IP text field.
        commandIPField = new JTextField(gs.getDefaultIP(), 10);
        commandIPField.setMaximumSize(commandIPField.getPreferredSize());
        commandIPField.setMinimumSize(commandIPField.getPreferredSize());
        commandIPField.setToolTipText("Enter the rover command IP address. (Default: " + 
                gs.getDefaultIP() + ")");
        commandIPPanel.add(commandIPField);
        commandIPPanel.add(Box.createHorizontalGlue());

        // Create command port panel.
        JPanel commandPortPanel = new JPanel();
        commandPortPanel.setLayout(new BoxLayout(commandPortPanel, BoxLayout.X_AXIS));
        connectionPanel.add(commandPortPanel);

        // Create command port label.
        JLabel commandPortLabel = new JLabel("Command Port:");
        commandPortPanel.add(commandPortLabel);
        commandPortPanel.add(Box.createHorizontalStrut(10));

        // Create command port text field.
        commandPortField = new JTextField(Integer.toString(gs.getDefaultPort()), 5);
        commandPortPanel.add(commandPortField);
        commandPortField.setMaximumSize(commandPortField.getPreferredSize());
        commandPortField.setMinimumSize(commandPortField.getPreferredSize());
        commandPortField.setToolTipText("Enter the rover command port number. (Default: " +
                gs.getDefaultPort() + ")");
        commandPortPanel.add(Box.createHorizontalGlue());

        // Create the service TCP port panel.
        JPanel serviceTCPPortPanel = new JPanel();
        serviceTCPPortPanel.setLayout(new BoxLayout(serviceTCPPortPanel, BoxLayout.X_AXIS));
        connectionPanel.add(serviceTCPPortPanel);

        // Create service TCP port label.
        JLabel serviceTCPPortLabel = new JLabel("Service TCP Port:");
        serviceTCPPortPanel.add(serviceTCPPortLabel);
        serviceTCPPortPanel.add(Box.createHorizontalStrut(10));

        // Create the service TCP port text field.
        int serviceTCPPort = gs.getServiceComm().getTCPPort();
        serviceTCPPortInputField = new JTextField(Integer.toString(serviceTCPPort), 5);
        serviceTCPPortInputField.setMaximumSize(serviceTCPPortInputField.getPreferredSize());
        serviceTCPPortInputField.setMinimumSize(serviceTCPPortInputField.getPreferredSize());
        serviceTCPPortInputField.setToolTipText("Enter the rover service TCP port number. (Default: " + 
                serviceTCPPort + ")");
        serviceTCPPortPanel.add(serviceTCPPortInputField);
        serviceTCPPortPanel.add(Box.createHorizontalGlue());

        // Create the service UDP port panel.
        JPanel serviceUDPPortPanel = new JPanel();
        serviceUDPPortPanel.setLayout(new BoxLayout(serviceUDPPortPanel, BoxLayout.X_AXIS));
        connectionPanel.add(serviceUDPPortPanel);

        // Create the service UDP port label.
        JLabel serviceUDPPortLabel = new JLabel("Service UDP Port:");
        serviceUDPPortPanel.add(serviceUDPPortLabel);
        serviceUDPPortPanel.add(Box.createHorizontalStrut(10));

        // Create the service UDP port text field.
        int serviceUDPPort = gs.getServiceComm().getUDPPort();
        serviceUDPPortInputField = new JTextField(Integer.toString(serviceUDPPort), 5);
        serviceUDPPortInputField.setMaximumSize(serviceUDPPortInputField.getPreferredSize());
        serviceUDPPortInputField.setMinimumSize(serviceUDPPortInputField.getPreferredSize());
        serviceUDPPortInputField.setToolTipText("Enter the rover service UDP port number. (Default: " + 
                serviceUDPPort + ")");
        serviceUDPPortPanel.add(serviceUDPPortInputField);
        serviceUDPPortPanel.add(Box.createHorizontalGlue());

        // Create connection button panel.
        JPanel connectionButtonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
        add(connectionButtonPanel, BorderLayout.SOUTH);

        // Create connection button.
        connectionButton = new JButton();
        boolean isConnected = gs.getCommandSender().isConnected();
        if (isConnected) {
            connectionButton.setText("Disconnect");
            connectionButton.setToolTipText("Disconnect from the rover.");
        }
        else {
            connectionButton.setText("Connect");
            connectionButton.setToolTipText("Connect to the rover.");
        }
        connectionButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // Attempt to connect or disconnect to the rover.
                        connectionUpdate();
                    }
                }).start();
            }
        });
        connectionButtonPanel.add(connectionButton);
    }
    
    /**
     * Attempt to connect or disconnect to the rover.
     */
    private void connectionUpdate() {
        CommandSender sender = gs.getCommandSender();
        if (sender.isConnected()) {
            // Attempt to disconnect from robot.
            try {
                // Disconnect from command sender.
                sender.disconnectUDP();
            }
            catch (IOException e) {
                connectionMessageLabel.setText("Error disconnecting from command: " + e.getMessage());
            }

            try {
                // Disconnect from service.
                gs.getServiceComm().disconnect();
            }
            catch (IOException e) {
                connectionMessageLabel.setText("Error disconnecting from service: " + e.getMessage());
            }

            connectionMessageLabel.setText("Robot not connected");
            connectionButton.setText("Connect");
            connectionButton.setToolTipText("Connect to the rover.");
        }
        else {
            boolean goodConnection = true;
            String ipAddress = commandIPField.getText();

            try {
                // Connect to command sender.
                gs.getCommandSender().setIPAddress(ipAddress);
                int port = Integer.parseInt(commandPortField.getText());
                gs.getCommandSender().setPort(port);
                sender.connectUDP();
            }
            catch (Exception e) {
                System.err.println("Command connection failed: " + e.getMessage());
                goodConnection = false;
            }

            System.out.println("Connected to command UDP");

            try {
                // Connect to service.
                gs.getServiceComm().setIPAddress(ipAddress);
                int serviceTCPPort = Integer.parseInt(serviceTCPPortInputField.getText());
                gs.getServiceComm().setTCPPort(serviceTCPPort);
                int serviceUDPPort = Integer.parseInt(serviceUDPPortInputField.getText());
                gs.getServiceComm().setUDPPort(serviceUDPPort);
                gs.getServiceComm().connect();
            }
            catch (Exception e) {
                System.err.println("Service connection failed: " + e.getMessage());
                goodConnection = false;
            }

            if (goodConnection) {
                connectionMessageLabel.setText("Connected to IP: " + sender.getIPAddress() + " port: "
                        + sender.getPort());
                connectionButton.setText("Disconnect");
                connectionButton.setToolTipText("Disconnect from the rover.");
            }
            else {
                connectionMessageLabel.setText("Cannot connect to IP: " + sender.getIPAddress() + " port: "
                        + sender.getPort());
                connectionButton.setText("Connect");
                connectionButton.setToolTipText("Connect to the rover.");

                // Disconnect sender if connected.
                try {
                    if (sender.isConnected()) sender.disconnectUDP();
                }
                catch (IOException e) {};

                // Disconnect services if connected.
                try {
                    gs.getServiceComm().disconnect();
                }
                catch (IOException e) {}
            }
        }
    }
}